#pragma once

#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include "Connection.hpp"
#include "Log.hpp"
#include "NetCal.hpp"

using namespace log_ns;

class HandlerConnection
{
    const static int _inbuffer_num = 4096;

public:
    HandlerConnection(handler_t process) : _process(process)
    {
    }
    void HandlerRecver(Connection *conn)
    {
        errno = 0;
        while (1)
        {
            char inbuffer[_inbuffer_num];
            ssize_t n = ::recv(conn->Sockfd(), inbuffer, sizeof(inbuffer) - 1, 0);
            if (n > 0)
            {
                inbuffer[n] = 0;
                conn->Appendinbuffer(inbuffer);
            }
            else
            {
                if (errno == EWOULDBLOCK)
                {
                    LOG(DEBUG, "fd:%d read done!\n", conn->Sockfd());
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    conn->_handler_excepter(conn);
                    return;
                }
            }
        }
        _process(conn);
        std::cout << conn->Inbuffer() << std::endl;
    }

    void HandlerSender(Connection *conn)
    {
        errno = 0;
        while (1)
        {
            int n = ::send(conn->Sockfd(), conn->Outbuffer().c_str(), conn->Outbuffer().size(), 0);
            if (n > 0)
            {
                conn->DiscardOutbuffer(n);
                if(conn->Outbuffer().empty()) 
                {
                    break;
                }
            }
            else if (n == 0)
            {
                break;
            }
            else
            {
                if (errno == EWOULDBLOCK)
                {
                    LOG(DEBUG, "fd:%d write pool full!\n", conn->Sockfd());
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    conn->_handler_excepter(conn);
                    return;
                }
            }
        }
        if(!conn->Outbuffer().empty())
        {
            conn->_R->EnableConnrctionReadWrite(conn->Sockfd(), 1, 1);
        }
        else
        {
            conn->_R->EnableConnrctionReadWrite(conn->Sockfd(), 1, 0);
        }
    }
    void HandlerExcepter(Connection *conn)
    {
        conn->_R->DelConnection(conn->Sockfd());
    }

private:
    handler_t _process;
};